﻿namespace LastfmNet.Api
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using LastfmNet;
    using LastfmNet.Models;

    /// <summary>
    /// Last.fm API event methods
    /// </summary>
    public class EventApi
    {
        /// <summary>
        /// Reference to the Lastfm host class
        /// </summary>
        private Lastfm lastfmApi;

        /// <summary>
        /// Initializes a new instance of the EventApi class.
        /// </summary>
        /// <param name="lastfmApi">Reference to the Lastfm host class</param>
        internal EventApi(Lastfm lastfmApi)
        {
            this.lastfmApi = lastfmApi;
        }

        /// <summary>
        /// Set a user's attendance status for an event. 
        /// This service requires authentication. 
        /// </summary>
        /// <param name="eventId">The numeric last.fm event id</param>
        /// <param name="attendanceStatus">The attendance status (0=Attending, 1=Maybe attending, 2=Not attending)</param>
        public void Attend(int eventId, AttendanceStatus attendanceStatus)
        {
            if (!this.lastfmApi.Session.Authenticated)
            {
                throw new LastfmNetException("This service requires authentication.");
            }

            LastfmParameters parameters = new LastfmParameters("event.attend");
            parameters["event"] = eventId.ToString(CultureInfo.InvariantCulture);
            parameters["status"] = ((int)attendanceStatus).ToString(CultureInfo.InvariantCulture);
            parameters.AddApiKey(this.lastfmApi.Session.ApiKey);
            parameters.AddSessionKey(this.lastfmApi.Session.SessionKey);
            parameters.Sign(this.lastfmApi.Session.ApiSecret);
            try
            {
                this.lastfmApi.MakeRequest(parameters, HttpMethod.Post);
            }
            catch (Exception ex)
            {
                throw new LastfmNetException("Unable to attent for the event! (" + ex.Message + ")", ex);
            }
        }

        /// <summary>
        /// Get a list of attendees for an event. 
        /// This service does not require authentication. 
        /// </summary>
        /// <param name="eventId">The numeric last.fm event id</param>
        /// <param name="page">The page number to fetch. Defaults to first page.</param>
        /// <param name="limit">The number of results to fetch per page. Defaults to 50.</param>
        /// <returns>A list of attendees for an event.</returns>
        public LastfmNet.Models.LastfmPager<LastfmNet.Models.User> GetAttendees(int eventId, int page = 1, int limit = 50)
        {
            LastfmParameters parameters = new LastfmParameters("event.getAttendees");
            parameters["event"] = eventId.ToString(CultureInfo.InvariantCulture);
            parameters["page"] = page.ToString(CultureInfo.InvariantCulture);
            parameters["limit"] = limit.ToString(CultureInfo.InvariantCulture);
            parameters.AddApiKey(this.lastfmApi.Session.ApiKey);
            try
            {
                LastfmResponse result = this.lastfmApi.MakeRequest(parameters);
                return new LastfmNet.Models.LastfmPager<LastfmNet.Models.User>(result.MainNode);
            }
            catch (Exception ex)
            {
                throw new LastfmNetException("Unable to get event attendees! (" + ex.Message + ")", ex);
            }
        }

        /// <summary>
        /// Get the metadata for an event on Last.fm. Includes attendance and lineup information. 
        /// This service does not require authentication. 
        /// </summary>
        /// <param name="eventId">The numeric last.fm event id</param>
        /// <returns>Event on Last.fm.</returns>
        public LastfmNet.Models.Event GetInfo(int eventId)
        {
            LastfmParameters parameters = new LastfmParameters("event.getInfo");
            parameters["event"] = eventId.ToString(CultureInfo.InvariantCulture);
            parameters.AddApiKey(this.lastfmApi.Session.ApiKey);
            try
            {
                LastfmResponse result = this.lastfmApi.MakeRequest(parameters);
                return new LastfmNet.Models.Event(result.MainNode);
            }
            catch (Exception ex)
            {
                throw new LastfmNetException("Unable to get event info! (" + ex.Message + ")", ex);
            }
        }

        /// <summary>
        /// Get shouts for this event. Also available as an rss feed.
        /// This service does not require authentication.
        /// </summary>
        /// <param name="eventId">The numeric last.fm event id</param>
        /// <param name="page">The page number to fetch. Defaults to first page.</param>
        /// <param name="limit">The number of results to fetch per page. Defaults to 50.</param>
        /// <returns>Shouts for this event</returns>
        public LastfmNet.Models.LastfmPager<LastfmNet.Models.Shout> GetShouts(int eventId, int page = 1, int limit = 50)
        {
            LastfmParameters parameters = new LastfmParameters("event.getShouts");
            parameters["event"] = eventId.ToString(CultureInfo.InvariantCulture);
            parameters["page"] = page.ToString(CultureInfo.InvariantCulture);
            parameters["limit"] = limit.ToString(CultureInfo.InvariantCulture);
            parameters.AddApiKey(this.lastfmApi.Session.ApiKey);
            try
            {
                LastfmResponse result = this.lastfmApi.MakeRequest(parameters);
                return new LastfmNet.Models.LastfmPager<LastfmNet.Models.Shout>(result.MainNode);
            }
            catch (Exception ex)
            {
                throw new LastfmNetException("Unable to get event shouts! (" + ex.Message + ")", ex);
            }
        }

        /// <summary>
        /// Share an event with one or more Last.fm users or other friends. 
        /// This service requires authentication. 
        /// </summary>
        /// <param name="eventId">An event ID</param>
        /// <param name="recipients">Email Address | Last.fm Username - A list of email addresses or Last.fm usernames. Maximum is 10. Email adresses are not supported!</param>
        /// <param name="public">Optionally show the share in the sharing users recent activity. Defaults to 0 (false).</param>
        /// <param name="message">An optional message to send with the recommendation. If not supplied a default message will be used.</param>
        public void Share(int eventId, IList<string> recipients, bool @public = false, string message = null)
        {
            // TODO: Not supporting emails? Why?
            if (!this.lastfmApi.Session.Authenticated)
            {
                throw new LastfmNetException("This service requires authentication.");
            }

            if (recipients == null)
            {
                throw new ArgumentNullException("You must give a list of recipients");
            }

            if (recipients.Count == 0 || recipients.Count > 10)
            {
                throw new ArgumentException("You must give at least one recipient and at most 10.");
            }

            LastfmParameters parameters = new LastfmParameters("event.share");
            parameters["event"] = eventId.ToString(CultureInfo.InvariantCulture);
            parameters["recipient"] = string.Join(",", recipients);
            parameters["public"] = @public.ToInteger().ToString(CultureInfo.InvariantCulture);
            if (message != null)
            {
                parameters["message"] = message;
            }

            parameters.AddApiKey(this.lastfmApi.Session.ApiKey);
            parameters.AddSessionKey(this.lastfmApi.Session.SessionKey);
            parameters.Sign(this.lastfmApi.Session.ApiSecret);
            try
            {
                this.lastfmApi.MakeRequest(parameters, HttpMethod.Post);
            }
            catch (Exception ex)
            {
                throw new LastfmNetException("Unable to share event! (" + ex.Message + ")", ex);
            }
        }

        /// <summary>
        /// Shout in this event's shoutbox
        /// This service requires authentication. 
        /// </summary>
        /// <param name="eventId">The id of the event to shout on</param>
        /// <param name="message">The message to post to the shoutbox</param>
        public void Shout(int eventId, string message)
        {
            if (!this.lastfmApi.Session.Authenticated)
            {
                throw new LastfmNetException("This service requires authentication.");
            }

            LastfmParameters parameters = new LastfmParameters("event.shout");
            parameters["event"] = eventId.ToString(CultureInfo.InvariantCulture);
            parameters["message"] = message;
            parameters.AddApiKey(this.lastfmApi.Session.ApiKey);
            parameters.AddSessionKey(this.lastfmApi.Session.SessionKey);
            parameters.Sign(this.lastfmApi.Session.ApiSecret);
            try
            {
                this.lastfmApi.MakeRequest(parameters, HttpMethod.Post);
            }
            catch (Exception ex)
            {
                throw new LastfmNetException("Unable to post shout on event! (" + ex.Message + ")", ex);
            }
        }
    }
}
